package lumis.portal.channel;

import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.cache.ICloneableCacheEntry;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.page.PageConfig;
import lumis.portal.serialization.operation.ICloneableConfig;
import lumis.portal.stability.StableMinor;
import lumis.portal.structure.GenericStructureElementPropertiesAccessor;
import lumis.portal.structure.ILayoutPropertiesAccessor;
import lumis.portal.structure.LayoutPropertiesHelper;
import lumis.portal.structure.StructureElement;
import lumis.portal.transaction.PortalTransactionFactory;
import lumis.util.EqualsUtil;
import lumis.util.XmlUtil;

import java.io.OutputStream;
import java.util.regex.Pattern;

import org.w3c.dom.Node;

/**
 *	Channel entity class 
 *	@since 4.0.0
 *	@version $Revision: 13093 $ $Date: 2011-05-28 18:40:18 -0300 (Sat, 28 May 2011) $
 */
@StableMinor(version = "6.0", sinceVersion = "4.0")
public class ChannelConfig extends StructureElement implements ICloneableCacheEntry, ICloneableConfig<ChannelConfig>
{
	public static final int CHANNEL_TYPE_BASIC = 0;
	public static final int CHANNEL_TYPE_LUMISADMIN = 1;

	public static final String PORTAL_CHANNEL_ID = "00000000F00000000000000000000001";
	public static final String LUMIS_ADMIN_CHANNEL_ID = "00000000B00000000000000000000001";

	/**
	 * The friendly path is generated using the parent channel's path and
	 * appending this channel's name
	 */
	public static final int FRIENDLY_PATH_TYPE_CHANNEL_NAME = 0;

	/** The friendly path is user defined. */
	public static final int FRIENDLY_PATH_TYPE_USER_DEFINED = 1;

	/** The friendly path is the same as this channel's parent friendly path. */
	public static final int FRIENDLY_PATH_TYPE_INHERIT = 2;

	/**
	 * Pattern used to detect managed properties for channels.
	 * @since 5.6.0
	 */
	private static final Pattern MANAGED_PROPERTIES_PATTERN = Pattern.compile("lumis\\.portal\\.(page|channel)\\..*");
	
	private String id = null;
	private String name = null;
	private String description = null;
	private int type = ChannelConfig.CHANNEL_TYPE_BASIC;
	private String parentId = null;
	private boolean hidden = false;
	private int position = 0;
	private boolean isTemplate = false;
	private String parentTemplateId = null;
	private String pageTemplateId = null;
	private int protocol = PageConfig.PAGE_PROTOCOL_INHERIT;
	@Deprecated
	private boolean inheritProtocol = true; //maintained for serialization compatibility 
	private boolean inheritStylesheet = true;
	private String accessControlListId = null;
	private int centerPages = PageConfig.PAGE_CENTER_INHERIT;
	private int layoutPagesType = PageConfig.PAGE_LAYOUT_TYPE_INHERIT;
	private boolean localGroups = false;
	private String localGroupPrefix = null;
	private String templateLocalGroupPrefix = null;
	private int cachePages = PageConfig.PAGE_CACHE_TYPE_INHERIT;
	private int friendlyPathType = ChannelConfig.FRIENDLY_PATH_TYPE_CHANNEL_NAME;
	private String friendlyPathUserDefined = null;
	private boolean inheritPageTemplate = true;
	private boolean inheritMetaTags = true;

	private Boolean automaticFriendlyId = true;
	private String friendlyId = null;
	
	//these fields were not renamed to keep compatibility with 4.2 LEC files
	private int pageRuntimeDataProviderType = PageConfig.PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_INHERIT;
	private String pageRuntimeDataProviderClassName = null;
	
	private String friendlyURLPattern;
	private boolean friendlyURLPatternEnabled;
	
	/**
	 * This element's property bag identifier.
	 * @since 5.0.0
	 */
	private String propertyBagId;
	
	/**
	 * The accessor for channel page layout attributes.
	 *
	 * @version $Revision: 13093 $ $Date: 2011-05-28 18:40:18 -0300 (Sat, 28 May 2011) $
	 * @since 5.6.0
	 */
	private static class ChannelLayoutPropertiesAccessor extends GenericStructureElementPropertiesAccessor implements ILayoutPropertiesAccessor
	{
		private final ChannelConfig channelConfig;
		
		public ChannelLayoutPropertiesAccessor(ChannelConfig channelConfig)
		{
			super(channelConfig);
			this.channelConfig = channelConfig;
		}
		
		public int getLayoutType()
		{
			return this.channelConfig.layoutPagesType;
		}

		public void setLayoutType(int layoutType)
		{
			this.channelConfig.layoutPagesType = layoutType;
			
		}
	}
	
	/**
	 * @since 5.6.0
	 */
	private LayoutPropertiesHelper layoutPropertiesHelper = new LayoutPropertiesHelper(new ChannelLayoutPropertiesAccessor(ChannelConfig.this));
	
	@Override
	protected Pattern getManagedPropertiesPattern()
	{
		return MANAGED_PROPERTIES_PATTERN;
	}
	
	@Override
	protected void loadPropertyBagValues() throws PortalException
	{
		super.loadPropertyBagValues();
	}
	
	@Override
	protected void applyPropertyBagChanges() throws PortalException
	{
		super.applyPropertyBagChanges();
	}
	
	/**
	 * Returns the path for the layout file for use by this channel.
	 * <p>
	 * The layout file is inherited to child elements and from parent. 
	 * <p>
	 * If {@link #getLayoutPagesType()} is not {@link PageConfig#PAGE_LAYOUT_TYPE_LAYOUT_FILE} (or inherited it),
	 * this method will return <code>null</code> since no layout file is to be used.
	 * 
	 * @return layoutFile the path for the layout file, relative to the <code>&lt;lumisdata&gt;/def</code> directory,
	 * possibly inherited from parent channel; or <code>null</code> if no layout file is to be used.
	 * 
	 * @see #getLayoutPagesType()
	 * @see #setLayoutFilePath(String)
	 * 
	 * @since 5.6.0
	 */
	public String getLayoutFilePath()
	{
		try
		{
			int layoutPagesType = ManagerFactory.getChannelManager().getLayoutPagesType(SessionConfig.getCurrentSessionConfig(), this, PortalTransactionFactory.getCurrentTransaction());
			if (layoutPagesType == PageConfig.PAGE_LAYOUT_TYPE_LAYOUT_FILE)
				return getPropertyValue(PageConfig.LAYOUT_FILE_PATH_PROPERTY_NAME);
			else
				return null;
		}
		catch (PortalException e)
		{
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * Sets the path for the layout file.
	 * <p>
	 * The path must be relative to the <code>&lt;lumisdata&gt;/def</code> directory, or
	 * <code>null</code> for inheriting the value from the parent channel.
	 * <p>
	 * The layout file is inherited to child elements.
	 * <p>
	 * The layout file property is applicable only if {@link #getLayoutPagesType()} is
	 * {@link PageConfig#PAGE_LAYOUT_TYPE_LAYOUT_FILE} or inherited this value.
	 * 
	 * @param layoutFile the path relative to the <code>&lt;lumisdata&gt;/def</code> directory, or
	 * <code>null</code> for inheriting the value from the parent channel.
	 * 
	 * @see #setLayoutPagesType(int)
	 * 
	 * @since 5.6.0
	 */
	public void setLayoutFilePath(String layoutFile)
	{
		layoutPropertiesHelper.setLayoutFilePath(layoutFile);
	}
	
	/**
	 * @return Returns the channelId.
	 */
	public String getId()
	{
		return id;
	}

	/**
	 * @param id
	 *            The channelId to set.
	 */
	public void setId(String id)
	{
		this.id = id;
	}

	/**
	 * @return Returns the description.
	 */
	public String getDescription()
	{
		return description;
	}

	/**
	 * @param description
	 *            The description to set.
	 */
	public void setDescription(String description)
	{
		this.description = description;
	}

	/**
	 * @return Returns the name.
	 */
	public String getName()
	{
		return name;
	}

	/**
	 * @param name
	 *            The name to set.
	 */
	public void setName(String name)
	{
		this.name = name;
	}

	/**
	 * @return Returns the hidden.
	 */
	public boolean isHidden()
	{
		return hidden;
	}

	/**
	 * @param hidden
	 *            The hidden to set.
	 */
	public void setHidden(boolean hidden)
	{
		this.hidden = hidden;
	}

	/**
	 * @return true if the Stylesheet was inherited and false otherwise.
	 */
	public boolean isInheritStylesheet()
	{
		return inheritStylesheet;
	}

	/**
	 * @return true if the Meta-Tags is inherited and false otherwise.
	 */
	public boolean isInheritMetaTags()
	{
		return inheritMetaTags;
	}
	/**
	 * @param inheritStylesheet
	 */
	public void setInheritStylesheet(boolean inheritStylesheet)
	{
		this.inheritStylesheet = inheritStylesheet;
	}
	
	/**
	 * @param inheritMetaTags
	 */
	public void setInheritMetaTags(boolean inheritMetaTags)
	{
		this.inheritMetaTags = inheritMetaTags;
	}

	/**
	 * @return Returns the inheritProtocol.
	 * @deprecated since 4.0.11.  This property is acquired via the {@link #getProtocol()} method.
	 */
	@Deprecated
	public boolean isInheritProtocol()
	{
		return inheritProtocol;
	}

	/**
	 * @param inheritProtocol
	 *            The inheritProtocol to set.
	 * @deprecated since 4.0.11.  This property is set via the {@link #setProtocol()} method.
	 */
	@Deprecated
	public void setInheritProtocol(boolean inheritProtocol)
	{
		this.inheritProtocol = inheritProtocol;
	}

	/**
	 * @return Returns the isTemplate.
	 */
	public boolean isTemplate()
	{
		return isTemplate;
	}

	/**
	 * @param isTemplate
	 *            The isTemplate to set.
	 */
	public void setTemplate(boolean isTemplate)
	{
		this.isTemplate = isTemplate;
	}

	/**
	 * @return Returns the pageTemplateId.
	 */
	public String getPageTemplateId()
	{
		return pageTemplateId;
	}

	/**
	 * @param pageTemplateId
	 *            The pageTemplateId to set.
	 */
	public void setPageTemplateId(String pageTemplateId)
	{
		this.pageTemplateId = pageTemplateId;
	}

	/**
	 * @return Returns the parentId.
	 */
	public String getParentId()
	{
		return parentId;
	}

	/**
	 * @param parentId
	 *            The parentId to set.
	 */
	public void setParentId(String parentId)
	{
		this.parentId = parentId;
	}

	/**
	 * @return Returns the position.
	 */
	public int getPosition()
	{
		return position;
	}

	/**
	 * @param position
	 *            The position to set.
	 */
	public void setPosition(int position)
	{
		this.position = position;
	}

	/**
	 * @return Returns the protocol.
	 */
	public int getProtocol()
	{
		return protocol;
	}

	/**
	 * @param protocol
	 *            The protocol to set.
	 */
	public void setProtocol(int protocol)
	{
		this.protocol = protocol;
	}

	/**
	 * @return Returns the type.
	 */
	public int getType()
	{
		return type;
	}

	/**
	 * @param type
	 *            The type to set.
	 */
	public void setType(int type)
	{
		this.type = type;
	}

	@Override
	public boolean equals(Object o)
	{
		if (!(o instanceof ChannelConfig))
			return false;
		ChannelConfig c = (ChannelConfig) o;

		return EqualsUtil.areEqual(id, c.id) && EqualsUtil.areEqual(name, c.name) && EqualsUtil.areEqual(description, c.description) && EqualsUtil.areEqual(parentId, c.parentId) && EqualsUtil.areEqual(hidden, c.hidden) && EqualsUtil.areEqual(position, c.position) && EqualsUtil.areEqual(isTemplate, c.isTemplate) && EqualsUtil.areEqual(parentTemplateId, c.parentTemplateId) && EqualsUtil.areEqual(pageTemplateId, c.pageTemplateId) && EqualsUtil.areEqual(protocol, c.protocol)
				&& EqualsUtil.areEqual(inheritStylesheet, c.inheritStylesheet) && EqualsUtil.areEqual(inheritMetaTags, c.inheritMetaTags) && EqualsUtil.areEqual(centerPages, c.centerPages) && EqualsUtil.areEqual(layoutPagesType, c.layoutPagesType) && EqualsUtil.areEqual(cachePages, c.cachePages) && EqualsUtil.areEqual(type, c.type) && EqualsUtil.areEqual(friendlyPathType, c.friendlyPathType);
	}

	/**
	 * @return Returns the accessControlListId.
	 */
	public String getAccessControlListId()
	{
		return accessControlListId;
	}

	/**
	 * @param accessControlListId
	 *            The accessControlListId to set.
	 */
	public void setAccessControlListId(String accessControlListId)
	{
		this.accessControlListId = accessControlListId;
	}

	@Override
	public String getPropertyBagId()
	{
		return propertyBagId;
	}

	/**
	 * Sets the property bag identifier.
	 * <p>
	 * This method should be used only for non-persisted channel, 
	 * because this property value may not be changed.
	 * @param propertyBagId The propertyBagId to set.
	 * @since 5.0.0
	 */
	protected void setPropertyBagId(String propertyBagId)
	{
		if (this.propertyBagId != null && !this.propertyBagId.equals(propertyBagId))
			throw new IllegalStateException("propertyBagId already set");
		
		this.propertyBagId = propertyBagId;
	}

	/**
	 * @return Returns the centerPages.
	 */
	public int getCenterPages()
	{
		return centerPages;
	}

	/**
	 * @param centerPages
	 *            The centerPages to set.
	 */
	public void setCenterPages(int centerPages)
	{
		this.centerPages = centerPages;
	}

	/**
	 * Returns the layout format for pages.
	 * 
	 * @return The layout format for pages.
	 */
	public int getLayoutPagesType()
	{
		return layoutPagesType;
	}

	/**
	 * Sets the layout format for pages.
	 * 
	 * @param layoutPagesType one of the valid page layout formats 
	 *            The layout format to set for pages.
	 */
	public void setLayoutPagesType(int layoutPagesType)
	{
		layoutPropertiesHelper.setLayoutType(layoutPagesType);
	}

	/**
	 * Sets the layout format for pages.
	 * 
	 * @param layoutPagesType one of the valid page layout formats 
	 *            The layout format to set for pages.
	 */
	protected void setLayoutPagesTypeInternal(int layoutPagesType)
	{
		this.layoutPagesType = layoutPagesType;
	}
	
	/**
	 * @return Returns the cachePages.
	 */
	public int getCachePages()
	{
		return cachePages;
	}

	/**
	 * @param cachePages
	 *            The cachePages to set.
	 */
	public void setCachePages(int cachePages)
	{
		this.cachePages = cachePages;
	}

	/**
	 * @return Returns the localGroups.
	 */
	public boolean hasLocalGroups()
	{
		return localGroups;
	}

	/**
	 * @param localGroups
	 *            The localGroups to set.
	 */
	public void setLocalGroups(boolean localGroups)
	{
		this.localGroups = localGroups;
	}

	/**
	 * @return Returns the localGroupPrefix.
	 */
	public String getLocalGroupPrefix()
	{
		return localGroupPrefix;
	}

	/**
	 * @param localGroupPrefix
	 *            The localGroupPrefix to set.
	 */
	public void setLocalGroupPrefix(String localGroupPrefix)
	{
		this.localGroupPrefix = localGroupPrefix;
	}

	/**
	 * Returns the template local group prefix. This attribute specifies
	 * the pattern used when applying a channel template.
	 * @return the template local group prefix.
	 * @since 4.0.6
	 */
	public String getTemplateLocalGroupPrefix() 
	{
		return templateLocalGroupPrefix;
	}

	/**
	 * Sets the template local group prefix.
	 * @param templateLocalGroupPrefix the value to set.
	 * @see #getTemplateLocalGroupPrefix()
	 * @since 4.0.6
	 */
	public void setTemplateLocalGroupPrefix(String templateLocalGroupPrefix) 
	{
		this.templateLocalGroupPrefix = templateLocalGroupPrefix;
	}

	public int getFriendlyPathType()
	{
		return friendlyPathType;
	}

	public void setFriendlyPathType(int friendlyPathType)
	{
		this.friendlyPathType = friendlyPathType;
	}

	public String getFriendlyPathUserDefined()
	{
		return friendlyPathUserDefined;
	}

	public void setFriendlyPathUserDefined(String friendlyPathUserDefined)
	{
		this.friendlyPathUserDefined = friendlyPathUserDefined;
	}

	/**
	 * Sets the channel's friendly identifier. This value must be unique among
	 * the channels contained in the same channel this channel is contained.
	 * 
	 * @param friendlyId
	 *            the channel's friendly identifier.
	 * @since 6.0.0
	 */
	public void setFriendlyId(String friendlyId)
	{
		this.friendlyId = friendlyId;
	}
	
	/**
	 * Generates a new friendly identifier and sets it as the friendly
	 * identifier of this channel. The friendly identifier is generated based
	 * on this channel's current name.
	 * <p>
	 * This method requires an active transaction.
	 * @see #setFriendlyId(String)
	 * @since 6.0.0
	 */
	public void setAutoGeneratedFriendlyId()
	{
		try
		{
			setFriendlyId(getAutomaticFriendlyId(getName()));
		}
		catch (PortalException e)
		{
			throw new RuntimeException(e);
		}
	}

	/**
	 * Returns the channel's friendly identifier.
	 * 
	 * @return the channel's friendly identifier.
	 * @since 6.0.0
	 */
	public String getFriendlyId()
	{
		return friendlyId;
	}

	/**
	 * Indicates whether the channel is going to use automatic generated
	 * friendly identifier or not.
	 * 
	 * @param automaticFriendlyId
	 *            indicates whether the channel is going to use automatic
	 *            generated friendly identifier or not.
	 * @since 6.0.0
	 */
	public void setAutomaticFriendlyId(boolean automaticFriendlyId)
	{
		this.automaticFriendlyId = automaticFriendlyId;
	}

	/**
	 * Returns whether the channel is going to use automatic generated friendly
	 * identifier or not.
	 * 
	 * @return whether the channel is going to use automatic generated friendly
	 *         identifier or not.
	 * @since 6.0.0
	 */
	public boolean isAutomaticFriendlyId()
	{
		return automaticFriendlyId;
	}

	@Override
	public ChannelConfig clone() throws CloneNotSupportedException
	{
		ChannelConfig clone = (ChannelConfig) super.clone();
		clone.layoutPropertiesHelper = new LayoutPropertiesHelper(new ChannelLayoutPropertiesAccessor(clone));
		return clone;
	}

	public void serialize(ChannelConfig channelConfig, OutputStream outputStream) throws PortalException
	{
		try
		{
			StringBuilder stream = new StringBuilder();

			stream.append("<channel id=\"" + getId() + "\">");
			stream.append("<name>" + XmlUtil.encodeXml(getName()) + "</name>");
			stream.append("<description>" + XmlUtil.encodeXml(getDescription()) + "</description>");
			stream.append("<parentId>" + (getParentId() == null ? "" : getParentId()) + "</parentId>");
			stream.append("<position>" + getPosition() + "</position>");
			stream.append("<type>" + getType() + "</type>");
			stream.append("<isTemplate>" + isTemplate() + "</isTemplate>");
			stream.append("<parentTemplateId>" + (getParentTemplateId() == null ? "" : getParentTemplateId()) + "</parentTemplateId>");
			stream.append("<aclId>" + (getAccessControlListId() == null ? "" : getAccessControlListId()) + "</aclId>");
			stream.append("<centerPages>" + getCenterPages() + "</centerPages>");
			stream.append("<layoutPagesType>" + getLayoutPagesType() + "</layoutPagesType>");
			stream.append("<cachePages>" + getCachePages() + "</cachePages>");
			stream.append("<hidden>" + isHidden() + "</hidden>");
			stream.append("<inheritStylesheet>" + isInheritStylesheet() + "</inheritStylesheet>");
			stream.append("<localGroupsPrefix>" + XmlUtil.encodeXml(getLocalGroupPrefix()) + "</localGroupsPrefix>");
			stream.append("<templateLocalGroupsPrefix>" + XmlUtil.encodeXml(getTemplateLocalGroupPrefix()) + "</templateLocalGroupsPrefix>");
			stream.append("<localGroups>" + hasLocalGroups() + "</localGroups>");
			stream.append("<pageTemplateId>" + (getPageTemplateId() == null ? "" : getPageTemplateId()) + "</pageTemplateId>");
			stream.append("<protocol>" + getProtocol() + "</protocol>");
			stream.append("<friendlyPathType>" + getFriendlyPathType() + "</friendlyPathType>");
			stream.append("<friendlyPathUserDefined>" + XmlUtil.encodeXml(getFriendlyPathUserDefined()) + "</friendlyPathUserDefined>");
			stream.append("<inheritPageTemplate>" + isInheritPageTemplate() + "</inheritPageTemplate>");
			stream.append("<inheritMetaTags>" + isInheritMetaTags() + "</inheritMetaTags>");
			stream.append("<propertyBagId>" + getPropertyBagId() + "</propertyBagId>");
			stream.append("<pageWebResourceDataProviderType>" + getPageWebResourceDataProviderType() + "</pageWebResourceDataProviderType>");
			stream.append("<pageWebResourceDataProviderClassName>" + (getPageWebResourceDataProviderClassName() == null ? "" : getPageWebResourceDataProviderClassName()) + "</pageWebResourceDataProviderClassName>");
			stream.append("<automaticFriendlyId>" + Boolean.toString(isAutomaticFriendlyId())
					+ "</automaticFriendlyId>");
			stream.append("<friendlyId>" + getFriendlyId() + "</friendlyId>");
			
			// serialize propertyBag
			stream.append(serializePropertyBag());
			
			stream.append("</channel>");

			outputStream.write(stream.toString().getBytes("UTF-8"));
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public void deserialize(Node channelNode) throws PortalException
	{
		try
		{
			setId(XmlUtil.readAttributeString("id", channelNode));
			setParentId(XmlUtil.readNodeString("parentId", channelNode));
			setName(XmlUtil.readNodeString("name", channelNode));
			setDescription(XmlUtil.readNodeString("description", channelNode));
			setLocalGroupPrefix(XmlUtil.readNodeString("localGroupsPrefix", channelNode));
			setTemplateLocalGroupPrefix(XmlUtil.readNodeString("templateLocalGroupsPrefix", channelNode));
			setPageTemplateId(XmlUtil.readNodeString("pageTemplateId", channelNode));
			setProtocol(XmlUtil.readNodeInt("protocol", channelNode, getProtocol()));
			setPosition(XmlUtil.readNodeInt("position", channelNode, getPosition()));
			setType(XmlUtil.readNodeInt("type", channelNode, getType()));
			setTemplate(XmlUtil.readNodeBoolean("isTemplate", channelNode, isTemplate()));
			setParentTemplateId(XmlUtil.readNodeString("parentTemplateId", channelNode, "").equals("") ? null : XmlUtil.readNodeString("parentTemplateId", channelNode));
			setAccessControlListId(XmlUtil.readNodeString("aclId", channelNode, "").equals("") ? null : XmlUtil.readNodeString("aclId", channelNode));
			setCenterPages(XmlUtil.readNodeInt("centerPages", channelNode, getCenterPages()));
			setLayoutPagesTypeInternal(XmlUtil.readNodeInt("layoutPagesType", channelNode, getLayoutPagesType()));
			setCachePages(XmlUtil.readNodeInt("cachePages", channelNode, getCachePages()));
			setHidden(XmlUtil.readNodeBoolean("hidden", channelNode, isHidden()));
			setInheritStylesheet(XmlUtil.readNodeBoolean("inheritStylesheet", channelNode, isInheritStylesheet()));
			setLocalGroups(XmlUtil.readNodeBoolean("localGroups", channelNode, hasLocalGroups()));
			setFriendlyPathType(XmlUtil.readNodeInt("friendlyPathType", channelNode, getFriendlyPathType()));
			setFriendlyPathUserDefined(XmlUtil.readNodeString("friendlyPathUserDefined", channelNode, getFriendlyPathUserDefined()));
			setInheritPageTemplate(XmlUtil.readNodeBoolean("inheritPageTemplate", channelNode, isInheritPageTemplate()));
			setInheritMetaTags(XmlUtil.readNodeBoolean("inheritMetaTags", channelNode, isInheritMetaTags()));
			setPropertyBagId(XmlUtil.readNodeString("propertyBagId", channelNode));
			setPageWebResourceDataProviderType(XmlUtil.readNodeInt("pageWebResourceDataProviderType", channelNode, PageConfig.PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_INHERIT));
			setPageWebResourceDataProviderClassName(XmlUtil.readNodeString("pageWebResourceDataProviderClassName", channelNode));
			setAutomaticFriendlyId(XmlUtil.readNodeBoolean("automaticFriendlyId", channelNode,
					isAutomaticFriendlyId()));
			setFriendlyId(XmlUtil.readNodeString("friendlyId", channelNode));
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public String getParentTemplateId()
	{
		return parentTemplateId;
	}

	public void setParentTemplateId(String parentTemplateId)
	{
		this.parentTemplateId = parentTemplateId;
	}

	public boolean isInheritPageTemplate()
	{
		return inheritPageTemplate;
	}

	public void setInheritPageTemplate(boolean inheritPageTemplate)
	{
		this.inheritPageTemplate = inheritPageTemplate;
	}
	
	/**
	 * Returns the page runtime data provider type.
	 * 
	 * The possible values are 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_INHERIT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_DEFAULT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_CONTENT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @return the runtime data provider type.
	 * @since 4.2.0
	 * 
	 * @deprecated Since 5.0.0 replaced by {@link #getPageWebResourceDataProviderType()}.
	 */
	@Deprecated
	public int getPageRuntimeDataProviderType()
	{
		return getPageWebResourceDataProviderType();
	}

	/**
	 * Sets the page runtime data provider type.
	 * 
	 * The possible values are 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_INHERIT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_DEFAULT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_CONTENT} or 
	 * {@value #PageConfig.PAGE_RUNTIME_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @param runtimeDataProviderType the runtime data provider type.
	 * @since 4.2.0
	 * 
	 * @deprecated Since 5.0.0 replaced by {@link #setPageWebResourceDataProviderType(int)}.
	 */
	@Deprecated
	public void setPageRuntimeDataProviderType(int runtimeDataProviderType)
	{
		setPageWebResourceDataProviderType(runtimeDataProviderType);
	}

	/**
	 * Returns the class name for the page runtime data provider.
	 * 
	 * This value should only be used if the runtime data provider type is {@value PAGE_RUNTIME_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @return the runtime data provider class name
	 * @since 4.2.0
	 * 
	 * @deprecated Since 5.0.0 replaced by {@link #getPageWebResourceDataProviderClassName()}.
	 */
	@Deprecated
	public String getPageRuntimeDataProviderClassName()
	{
		return getPageWebResourceDataProviderClassName();
	}

	/**
	 * Sets the runtime data provider class name.
	 * 
	 * @param runtimeDataProviderClassName the class name to be set.
	 * @since 4.2.0
	 * 
	 * @deprecated Since 5.0.0 replaced by {@link #setPageWebResourceDataProviderClassName(String)}.
	 */
	@Deprecated
	public void setPageRuntimeDataProviderClassName(String runtimeDataProviderClassName)
	{
		setPageWebResourceDataProviderClassName(runtimeDataProviderClassName);
	}

	/**
	 * Returns the class name for the page web resource data provider.
	 * <p>
	 * This value should only be used if the page web resource data provider 
	 * type is {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @return the runtime data provider class name
	 * @since 5.0.0
	 */
	public String getPageWebResourceDataProviderClassName()
	{
		return pageRuntimeDataProviderClassName;
	}

	/**
	 * Sets the page web resource provider class name.
	 * 
	 * @param providerClassName the class name to be set.
	 * @since 5.0.0
	 */
	public void setPageWebResourceDataProviderClassName(String providerClassName)
	{
		this.pageRuntimeDataProviderClassName = providerClassName;
	}

	/**
	 * Returns the page web resource data provider type.
	 * 
	 * The possible values are 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_INHERIT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_DEFAULT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_CONTENT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @return the page web resource data provider type.
	 * @since 5.0.0
	 */
	public int getPageWebResourceDataProviderType()
	{
		return pageRuntimeDataProviderType;
	}

	/**
	 * Sets the page web resource data provider type.
	 * 
	 * The possible values are 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_INHERIT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_DEFAULT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_CONTENT} or 
	 * {@link PageConfig#PAGE_WEB_RESOURCE_DATA_PROVIDER_TYPE_CUSTOM}
	 * 
	 * @param providerType the page web resource data provider type.
	 * @since 5.0.0
	 */
	public void setPageWebResourceDataProviderType(int providerType)
	{
		this.pageRuntimeDataProviderType = providerType;
	}

	/**
	 * Returns the friendly URL pattern specific for this channel (non-inheritable).
	 * @return the friendlyURLPattern the pattern, or <code>null</code> if it
	 * is not set for this channel.
	 * @since 5.0.0
	 */
	public String getFriendlyURLPattern()
	{
		return friendlyURLPattern;
	}
	
	/**
	 * Sets the friendly URL pattern specific for this channel (non-inheritable).
	 * @param friendlyURLPattern the pattern.
	 * @since 5.0.0
	 */
	public void setFriendlyURLPattern(String friendlyURLPattern)
	{
		this.friendlyURLPattern = friendlyURLPattern;
	}

	/**
	 * Returns if the friendly URL pattern specific for this channel 
	 * (non-inheritable) is enabled.
	 * @return <code>true</code> if enabled, <code>false</code> if disabled.
	 * @since 5.0.0
	 */
	public boolean isFriendlyURLPatternEnabled()
	{
		return friendlyURLPatternEnabled;
	}
	
	/**
	 * Sets if the friendly URL pattern specific for this channel 
	 * (non-inheritable) is enabled.
	 * @param friendlyURLPatternEnabled <code>true</code> to enable, 
	 * <code>false</code> to disable.
	 * @since 5.0.0
	 */
	public void setFriendlyURLPatternEnabled(boolean friendlyURLPatternEnabled)
	{
		this.friendlyURLPatternEnabled = friendlyURLPatternEnabled;
	}

	@Override
	protected boolean mayUseFriendlyId(String friendlyId) throws PortalException
	{
		return ((ChannelManager) ManagerFactory.getChannelManager()).mayUseFriendlyId(this,
				friendlyId);
	}

	@Override
	protected int getFriendlyIdMaxLength()
	{
		return 30;
	}
}
